#ifndef cope_cc_
#define cope_cc_

#include "cope.h"
#include <iostream>
#include <iomanip>


#define G 0.8


/* ======================================================================
   COPEHeaderClass
   ===============

   ====================================================================== */
int hdr_cope::offset_;

static class CopeHeaderClass : public PacketHeaderClass {
public:
    CopeHeaderClass() : PacketHeaderClass("PacketHeader/Cope",
					  sizeof(hdr_cope)) {
	bind_offset(&hdr_cope::offset_);
    }
} class_hdr_cope;

/* ======================================================================
   COPEClass
   =========

   ====================================================================== */       
static class COPEClass : public TclClass 
{
public:
    COPEClass() : TclClass("COPE") {

    }
    TclObject* create(int, const char*const*) {
        return (new COPE);        
    }    
    
} class_cope;


/* ======================================================================
   COPEHandler
   ===========
                   
   ====================================================================== */
void COPEHandler::handle(Event*) {
  
    cope_inst_->cope_resume();
}       
// Duplicate acks and more than 8 acks
void AckPendHandler::handle(Event* e) {
    // create ctrl pkt and send out
    cope_inst_->ctrl_pkt_handler(e->handler_);
}

// Problem!! Where to call this function to start gc!!!!???
void PacketPoolHandler::start() {
    Scheduler& s = Scheduler::instance();
    first_ = true;

    s.schedule(&cope_inst_->h_pkt_pool_,
	       &cope_inst_->pool_event_,
	       cope_inst_->gc_interval_);
}

/*
 * To handle the garbage collection every gc_interval time.
 * However, for the first period, just reset the b_expired flag,
 * that means keep the previous period packets one more period.
 */
void PacketPoolHandler::handle(Event* e) {
    Scheduler& s = Scheduler::instance();

    //    if(cope_inst_->node_->nodeid() == 1) {
    // cout << cope_inst_->node_->nodeid()
    //      << " -------------------before---------------" << endl;
    // cope_inst_->pkt_pool_->showPool();
    //    }
    
    // if(first_) {
    // 	cope_inst_->pkt_pool_->b_expired_ = !cope_inst_->pkt_pool_->b_expired_;
    // 	first_ = false;
    // }
    // else {
	// cout << "garbage collection" << endl;
	cope_inst_->pkt_pool_->garbage_collection(cope_inst_);	
    // }

    s.schedule(&cope_inst_->h_pkt_pool_,
	       &cope_inst_->pool_event_,
	       cope_inst_->gc_interval_);

    //    if(cope_inst_->node_->nodeid() == 1) {
    // cout << cope_inst_->node_->nodeid()
    //      << " -------------------after-----------------" << endl;
    // cope_inst_->pkt_pool_->showPool();
    //    }
}

/* ======================================================================
   COPE
   ====
				  
   ====================================================================== */
// these two parameters should be put into the command() function???

COPE::COPE() : ctrl_pkt_timer_(this),
	       h_cope_(this),
	       h_ack_pend_(this), 
	       h_pkt_pool_(this) {
   
 
    non_ack_timers_ = new list<NonAckTimer*>;
    cope_prq_ = NULL;
    cope_index_ = 0;
    //gc_interval_ = 5.0;
    bind("gc_interval_", &gc_interval_);
    bind("txtime_factor_", &txtime_factor_);    
}

COPE::~COPE() {
    COPE_ND_CLEAR(COPELocalCounter, &local_counter_list_);
    list<NonAckTimer*>::iterator it = non_ack_timers_->begin();
    for( ; it != non_ack_timers_->end(); ) {
	delete (*it);
	it = non_ack_timers_->erase(it);
    }
    delete non_ack_timers_;

    delete cope_prq_;
    delete prob_guess_;
    delete non_acks_;
    delete pend_acks_;
    delete pkt_pool_;
    delete pkt_info_;
}
double COPE::txtime(Packet * p) {

    //double t = mac_->txtime(HDR_CMN(p)->size(), mac_->dataRate_);
    //cout << "execute time is " << t << endl;
    //double t = mac_->txtime(1500, mac_->dataRate_);
    //return txtime_factor_ * t;
    return txtime_factor_ * 0.01; //???should change back TCP
    //return txtime_factor_ * 0.008;//UDP

}

int COPE::command(int argc, const char*const* argv) {
  
    if(argc == 3) {
	// In tcl, add-node should be called prior to cope-init
	if (strcmp(argv[1],"add-node") == 0) {
	    assert(argv[2] == NULL);
	    node_ = (MobileNode *)TclObject::lookup(argv[2]);
	    return (TCL_OK);
	} else if (strcmp(argv[1], "add-mac") == 0) {
	    mac_ = (Mac802_11 *)TclObject::lookup(argv[2]);
	    assert(mac_);
	    mac_->installCopeTap(this);
	    return (TCL_OK);
	} else if (strcmp(argv[1], "cope-init") == 0) {
	  
	    // init cope_prq
	    cope_prq_ = new COPEPriQueue();
	
	    //init prob_guess_
	    prob_guess_ = new ProbGuess(node_);
                
	    //init ack queues
	    non_acks_ = new NonAckQueue(); 
	    pend_acks_ = new AckPendQueue(); 
                
	    //init packet pool
	    pkt_pool_ = new PacketPool();

	    //init packet info
	    pkt_info_ = new PacketInfo();

	    
	    LIST_INIT(&local_counter_list_);

	    // timers start
	    h_pkt_pool_.start();
	    ctrl_pkt_timer_.start(CTRL_PKT_PEROID);

	    cope_prq_->setCOPEHandler(&h_cope_);
	}
    }
    // call cope_prq_'s command to set targets, and judge dsr or not 
    if(cope_prq_ != NULL) 
	return cope_prq_->command(argc, argv);
    else
	return TCL_OK;      

}

void COPE::getNeighborList( nb_head * neighbor_list) {
    int local_nd_id = node_->nodeid();
    for (int i = 0; i < God::instance()->nodes(); i++) {
	int nb_id = (God::instance()->getNodes())[i]->nodeid();
	if((local_nd_id != nb_id) 
	   && 
	   ( God::instance()->IsNeighbor(local_nd_id, nb_id) == true))
	    COPE_ND_INSERT(COPENeighbor, neighbor_list, nb_id, 0);
    }
}

void COPE::initNeighborCounters( local_counter_head * counter_list) {
    int local_nd_id = node_->nodeid();
    for (int i = 0; i < God::instance()->nodes(); i++) {
	int nb_id = (God::instance()->getNodes())[i]->nodeid();
	if((local_nd_id != nb_id) 
	   && 
	   ( God::instance()->IsNeighbor(local_nd_id, nb_id) == true))
	    COPE_ND_INSERT(COPELocalCounter, counter_list, nb_id, 0);
    }
}

/*
 * Overhear packets from neighbors, only sendup packets not sent to me
 */
void COPE::tap(const Packet* p) {
    int prev_hop = ETHER_ADDR(HDR_MAC802_11(p)->dh_ta);
    if(prev_hop == node_->address()
       || HDR_CMN(p)->next_hop() == node_->address()
       || HDR_CMN(p)->next_hop() < 0)
	return;

    Packet* pp = p->copy();
    // if(HDR_CMN(pp)->uid_ == 50
    //    && (node_->nodeid() == 4)) {
    // 	cout << "Tap->time: " << CUR_TIME
    // 	     << " node: " << node_->nodeid()
    // 	     << " uid: " << HDR_CMN(pp)->uid_
    // 	     << " ptype: " << HDR_CMN(pp)->ptype()
    // 	     << " size " << HDR_CMN(pp)->size()
    // 	     << " prev: " << ETHER_ADDR(HDR_MAC802_11(pp)->dh_ta)
    // 	     << " next: " << HDR_CMN(pp)->next_hop();

    // 	if(HDR_CMN(pp)->ptype() == PT_TCP)
    // 	    cout << " TCP seq: " << HDR_TCP(pp)->seqno();
    // 	else if(HDR_CMN(pp)->ptype() == PT_ACK)
    // 	    cout << " ACK seq: " << HDR_TCP(pp)->seqno();
    // 	cout << endl;
    // }
    
    recv(pp, (Handler*)0);
}

/*
 * called by upper or lower layer
 */
void COPE::recv(Packet * p, Handler * h) {
    struct hdr_cmn *ch = HDR_CMN(p);

    if(cope_prq_->isEmpty())
	ctrl_pkt_timer_.start(CTRL_PKT_PEROID);

    /*-------------------DOWN------------------------------*/
    if(ch->direction() == hdr_cmn::DOWN) {
          
	/* If I am the source node, set cope pkt header
	   and put p into packet pool */

	// if(node_->nodeid() == 5) {
	//     cout << "Down->time: " << CUR_TIME
	// 	 << " node: " << node_->nodeid()
	// 	 << " uid: " << HDR_CMN(p)->uid_
	// 	 << " ptype: " << HDR_CMN(p)->ptype()
	// 	 << " size " << HDR_CMN(p)->size()
	// 	 << " prev: " << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
	// 	 << " next: " << HDR_CMN(p)->next_hop();
	//     if(HDR_CMN(p)->ptype() == PT_TCP)
	// 	cout << " TCP seq: " << HDR_TCP(p)->seqno();
	//     else if(HDR_CMN(p)->ptype() == PT_ACK)
	// 	cout << " ACK seq: " << HDR_TCP(p)->seqno();
	//     cout << endl;
	// }

	if( HDR_CMN(p)->ptype() == PT_CBR
	    || (HDR_CMN(p)->ptype() == PT_TCP && HDR_TCP(p)->seqno() > 0)
	    || (HDR_CMN(p)->ptype() == PT_ACK && HDR_TCP(p)->seqno() > 0)
	    || HDR_CMN(p)->ptype() == PT_COPE ) {
	    cope_prq_->cope_prq_senddown(p, this);     
	    return;

	} else {
	    // if(node_->nodeid() == 11 && HDR_CMN(p)->uid_ == 4885) {
	    // 	cout << "recvdown->time: " << CUR_TIME
	    // 	     << " node: " << node_->nodeid()
	    // 	     << " uid: " << HDR_CMN(p)->uid_
	    // 	     << " ptype: " << HDR_CMN(p)->ptype()
	    // 	     << " size " << HDR_CMN(p)->size()
	    // 	     << " prev: " << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
	    // 	     << " next: " << HDR_CMN(p)->next_hop()
	    // 	     << " ncnum: " << (int)HDR_COPE(p)->encoded_num_
	    // 	     << endl;
	    // }
		
	    if(cope_prq_->dsr_)
		cope_prq_->CMUPriQueue::recv(p, h); 
	    else
		cope_prq_->PriQueue::recv(p, h);	
	}

	/*-----------------UP------------------------------*/
    } else {                               	
	struct hdr_cmn* ch = HDR_CMN(p);
	nsaddr_t next_hop = ch->next_hop();
	if(ch->ptype() == PT_TCP || ch->ptype() == PT_ACK) {
	    if(next_hop == node_->nodeid() && HDR_TCP(p)->seqno() == 0) {
		// if(HDR_COPE(p)->encoded_num_ > 0)
		//     cout << "start: num: "
		// 	 << HDR_COPE(p)->encoded_num_ << endl;
	        (cope_prq_->up_target_)->recv(p, (Handler *) 0);
		return;
	    } else if(next_hop != node_->nodeid() && HDR_TCP(p)->seqno() == 0) {
		return;
	    }
	}
	   
	if( HDR_CMN(p)->ptype() != PT_CBR
	    && HDR_CMN(p)->ptype() != PT_TCP
	    && HDR_CMN(p)->ptype() != PT_ACK
	    && HDR_CMN(p)->ptype() != PT_COPE ) {
	    if(next_hop == node_->nodeid() || next_hop < 0) {
		// if((int)HDR_COPE(p)->encoded_num_ > 0) {
		//     cout << "x: num: "
		// 	 << (int)HDR_COPE(p)->encoded_num_ << endl;
		//     cout << "x->time: " << CUR_TIME
		// 	 << " node: " << node_->nodeid()
		// 	 << " uid: " << HDR_CMN(p)->uid_
		// 	 << " ptype: " << HDR_CMN(p)->ptype()
		// 	 << " size " << HDR_CMN(p)->size()
		// 	 << " prev: " << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
		// 	 << " next: " << HDR_CMN(p)->next_hop();
		//     if(HDR_CMN(p)->ptype() == PT_TCP)
		// 	cout << " TCP seq: " << HDR_TCP(p)->seqno();
		//     else if(HDR_CMN(p)->ptype() == PT_ACK)
		// 	cout << " ACK seq: " << HDR_TCP(p)->seqno();
		//     cout << endl;
		// }

		(cope_prq_->up_target_)->recv(p, (Handler *) 0);		
	    }
	    return;
	}

	Packet* cp = p->copy();
	Packet** recv_pkt = &cp;
	int prev_hop = ETHER_ADDR(HDR_MAC802_11(p)->dh_ta);

	/* only for PT_CBR & PT_COPE are enough    */
	/* update the packet info for previous hop */
	pkt_info_->update_pkt_info( p, prev_hop ); 

	/* update the packet info for source node  */
        pkt_info_->update_pkt_info( p, HDR_IP(p)->saddr() );
	

	// cout << " copeid: " << HDR_CMN(*recv_pkt)->cope_pkt_id() 
	//      << " uid: " << HDR_CMN(*recv_pkt)->uid_
	//      << " pt: " << HDR_CMN(p)->ptype()
	//      << " time: " << CUR_TIME << " "
	//      << " prev: " 
	//      << ETHER_ADDR(HDR_MAC802_11(*recv_pkt)->dh_ta)
	//      <<" next: " 
	//      << HDR_CMN(*recv_pkt)->next_hop();
	// if(HDR_CMN(*recv_pkt)->ptype() == PT_TCP)
	//     cout << " TCP seq: " << HDR_TCP(*recv_pkt)->seqno();
	// else if(HDR_CMN(*recv_pkt)->ptype() == PT_ACK)
	//     cout << " ACK seq: " << HDR_TCP(*recv_pkt)->seqno();
	// cout << endl;
	
	/* native or decodable packet which is recievable */
	int recv_tag = receivable(recv_pkt);
	
	/* put a copy of  recv_pkt into packet pool, it could be:
	 * 1. an decoded native packet(decodable == 1)
	 * 2. a normal native packet (native == 1) 
	 * 3. an encoded cope packet
	 */
	
	if (recv_tag == 1 || recv_tag == 2) {   // native
	    if(recv_tag == 1) { // native and receivable
	        if( HDR_COPE(*recv_pkt)->ctype_ == COPE_RETX) {
		    int prev = ETHER_ADDR(HDR_MAC802_11(*recv_pkt)->dh_ta);
		    u_int16_t loc = HDR_COPE(*recv_pkt)->xoreds_[0].local_seq_num_;
		    if(loc > 0) {
			HDR_COPE(*recv_pkt)->ctype_ = COPE_DATA;
			HDR_COPE(*recv_pkt)->xoreds_[0].local_seq_num_ = 0;
			pend_acks_->enqueue_pend(prev, loc, false, this);
		    }
		}
		pkt_pool_->in_pool(*recv_pkt, this);
		// if(HDR_COPE(*recv_pkt)->encoded_num_ > 0)
		//     cout << "native: num: " << HDR_COPE(*recv_pkt)->encoded_num_ << endl;
		(cope_prq_->up_target_)->recv(*recv_pkt, (Handler *) 0);
	    } else {
//	    	pkt_pool_->in_pool(p->copy());	    
	    	pkt_pool_->in_pool(*recv_pkt, this);
		//		Packet::free(p);
		Packet::free(*recv_pkt);
	    }
	    Packet::free(p);
	    //	    return;
	} else if (recv_tag == 3) { // encoded and decodable packet 
	    HDR_CMN(*recv_pkt)->direction() = hdr_cmn::UP;
	    if( HDR_COPE(*recv_pkt)->ctype_ == COPE_RETX ) {
		HDR_COPE(*recv_pkt)->ctype_ = COPE_DATA;
	    } else {

	        // cout << " copeid: " << HDR_CMN(*recv_pkt)->cope_pkt_id() 
		//      << " uid: " << HDR_CMN(*recv_pkt)->uid_
		//      << " pt: " << HDR_CMN(p)->ptype()
		//      << " time: " << CUR_TIME << " "
		//      << " prev: " 
		//      << ETHER_ADDR(HDR_MAC802_11(*recv_pkt)->dh_ta)
		//      <<" next: " 
		//      << HDR_CMN(*recv_pkt)->next_hop();
		// if(HDR_CMN(*recv_pkt)->ptype() == PT_TCP)
		//     cout << " TCP seq: " << HDR_TCP(*recv_pkt)->seqno();
		// else if(HDR_CMN(*recv_pkt)->ptype() == PT_ACK)
		//     cout << " ACK seq: " << HDR_TCP(*recv_pkt)->seqno();
		// cout << endl;
		
//		pkt_pool_->in_pool((*recv_pkt)->copy());
		pkt_pool_->in_pool(*recv_pkt, this);
	    }
	    
	    // cout << HDR_CMN(p)->cope_pkt_id() 
	    // 	 << " " << HDR_CMN(p)->uid_
	    // 	 << " " << HDR_CMN(p)->ptype()
	    // 	 << " " << CUR_TIME << " "
	    // 	 << " prev: " << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
	    // 	 <<" next: " << HDR_CMN(p)->next_hop() << endl;
	    
	   

	    /* 
	     * send pkt to upper layer target, actually the handler
	     * is unuseful for the uptarget_, and it's not reasonable
	     * to pass h_cope_ as a handler 
	     */
	    // if(HDR_COPE(*recv_pkt)->encoded_num_ > 0)
	    // 	cout << "decoded: num: " << HDR_COPE(*recv_pkt)->encoded_num_ << endl;
	    (cope_prq_->up_target_)->recv(*recv_pkt, (Handler *) 0);
	    Packet::free(p);
	     
	    // encoded but non decodable packet || but overhear packet
	} else if ( recv_tag == 0 || recv_tag == -1 ) { 
	    
	    /* here include overhear packet and non-decodable packet, 
	       we judge them together since packet pool will drop the
	       encoded packet anyway */
	  
	    if (recv_tag == -1) { // an overhear encoded packet
	
		// pool_state <<  "o " <<HDR_CMN(p)->cope_pkt_id()
		// 	   << " " << HDR_CMN(p)->uid_
		// 	   << " " << HDR_CMN(p)->ptype()
		// 	   << " " << CUR_TIME << " "
		// 	   << " prev: " << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
		// 	   <<" next: " << HDR_CMN(p)->next_hop() << endl;
	      	     
		// cout << HDR_CMN(p)->cope_pkt_id() 
		//       << " " << HDR_CMN(p)->uid_
		//       << " " << HDR_CMN(p)->ptype()
		//       << " " << CUR_TIME << " "		  
		//       << " prev: " << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
		//       <<" next: " << HDR_CMN(p)->next_hop() << endl;

		// pkt_pool_->in_pool(p->copy()); //drop

	    } else { // an non decodable packet

	        // pool_state << "t " <<HDR_CMN(p)->cope_pkt_id()
		// 	   << " " << HDR_CMN(p)->uid_
		// 	   << " " << HDR_CMN(p)->ptype()
		// 	   << " " << CUR_TIME << " " 
		// 	   << " prev: " 
		// 	   << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
		// 	   << " next: " 
		// 	   << HDR_CMN(p)->next_hop() << endl;
	
		// cout << HDR_CMN(p)->cope_pkt_id() 
		//       << " " << HDR_CMN(p)->uid_
		//       << " " << HDR_CMN(p)->ptype()
		//       << " " << CUR_TIME << " "
		//       << " prev: " 
		//       << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
		//       << " next: " 
		//       << HDR_CMN(p)->next_hop() << endl;
		
		// pkt_pool_->in_pool(p->copy()); //drop

	    }	    
	    Packet::free(p);
	    Packet::free(*recv_pkt);
	} else { //COPE_CTRL packet
	    // cout << HDR_CMN(p)->cope_pkt_id() 
	    // 	  << " " << HDR_CMN(p)->uid_
	    // 	  << " " << HDR_CMN(p)->ptype()
	    // 	  << " " << CUR_TIME << " "
	    // 	  << " prev: " 
	    // 	  << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
	    // 	  << " next: " 
	    // 	  << HDR_CMN(p)->next_hop() << endl;
	    Packet::free(p);
	    Packet::free(*recv_pkt);

	}
    } 
}

void COPE::cope_resume(){
    cope_prq_->cope_prq_resume(this);
}



/**
 * return whether a encoded packet(true) or native packet(flase)
 */
int COPE::encode(Packet * p, Packet ** res_pkt, Packet** max_size_pkt) {
 
    nb_head remain_ndlist;
    LIST_INIT(&remain_ndlist);
    nb_pkt_head cope_next_hops;
    LIST_INIT(&cope_next_hops); 

    //    if(node_->nodeid() == 1) {
    // cout << setw(10) << "encode "
    //      << setw(10) << Scheduler::instance().clock()
    //      << setw(8) << HDR_CMN(p)->uid_
    //      << setw(8) << HDR_TCP(p)->seqno()
    //      << setw(8) << HDR_CMN(p)->cope_pkt_id()
    //      << setw(8) << HDR_CMN(p)->next_hop();
    // if(HDR_CMN(p)->ptype() == PT_ACK)
    //     //		    cope_inst->qout
    //     cout << setw(8) << "ack" << endl;
    // else if(HDR_COPE(p)->ctype_ == COPE_RETX)
    //     //		    cope_inst->qout
    //     cout << setw(8) << "crx" << endl;
    // else
    //     //		    cope_inst->qout << endl;
    //     cout << endl;

    //	cope_prq_->showQueue(this);
    //    }
    
    //get the neighbor list
    getNeighborList(&remain_ndlist);
    
    // make a copy of p firstly, the passed res_pkt = p
    //res_pkt = p->copy();

    //get the next hop of packet res_pkt
    struct hdr_cmn* ch = HDR_CMN(*res_pkt);
    nsaddr_t next_hop_addr = ch->next_hop();
    int next_hop_id_p = (Node::get_node_by_address(next_hop_addr))->nodeid();   
 
    // insert the next hop into NEXTHOPS
    // note that original p is inserted rather than res_pkt
    COPE_ND_INSERT(COPENeighborPkt, &cope_next_hops, next_hop_id_p, p);
  
    //delete the next hop from cope's remained node list
    COPE_ND_DELETE(COPENeighbor, remain_ndlist, next_hop_id_p);

    // cope_prq_->showQueue(this);COPENeighbor
    // cope_prq_->cope_vir_table_->show();
 
    //iterate nodeid from remained node list 
    if(ch->size() >= PACKET_SIZE_THRESHOLD) {
	//for large virqueue first
	traverse_remained_nbs('L', &cope_next_hops, &remain_ndlist);
	traverse_remained_nbs('S', &cope_next_hops, &remain_ndlist);
    } else {
	//for small virqueue first
	traverse_remained_nbs('S', &cope_next_hops, &remain_ndlist);
	traverse_remained_nbs('L', &cope_next_hops, &remain_ndlist);
    }

    // cope_prq_->showQueue(this);
    // cope_prq_->cope_vir_table_->show();
    
    //xor the packet to encoded packet data and 
    //put this pkt infomation into cope header

    // assemble HDR_COPE
    COPENeighborPkt* cope_iter; 
    COPE_GET_HEAD(&cope_next_hops, cope_iter); 
    COPE_GET_NEXT(cope_iter, cope_iter); 
  
    //xor res_pkt(copy of p) into cope header
    

    if( cope_iter != NULL ) { 
	HDR_COPE(*res_pkt)->encoded_num_ = 0;
	double max_size = 0.0;

	COPE_GET_HEAD(&cope_next_hops, cope_iter); 
      
	COPELocalCounter* local = NULL;
     
	// cout << "ENCODE" << endl;
	do {
	    /* add xor headers */
	    hdr_xored_t hdr_xored_pkt;
	    hdr_xored_pkt.pkt_id_ = cope_iter->get_pkt_id();
	    hdr_xored_pkt.nexthop_ = cope_iter->getid();
	 
	    if(HDR_COPE( cope_iter->get_pkt())->ctype_ == COPE_RETX) {
	  
		hdr_xored_pkt.local_seq_num_ =  
		    non_acks_->get_local_seq(hdr_xored_pkt.nexthop_,
					     hdr_xored_pkt.pkt_id_);
	            	  
		if(hdr_xored_pkt.local_seq_num_ == 0)
		    return 0;

	    } else {

		/* increase the local sequence number for each next hop */
		// lookup the local seq-num counter for a specific node
		COPE_ND_LOOKUP(COPELocalCounter, 
			       local_counter_list_, 
			       cope_iter->getid(), 
			       local);
	      
		if(!local) { // this is a new neighbor
		    // firstly, insert this new neighbor
		    COPE_ND_INSERT(COPELocalCounter,
				   &local_counter_list_,
				   cope_iter->getid(),
				   0);
		    // then, get this neighbor's COPELocalCounter*
		    COPE_ND_LOOKUP(COPELocalCounter, 
				   local_counter_list_,
				   cope_iter->getid(), 
				   local);
		}
		// if local_seq_counter_ > 2^16 - 1 ?
		local->local_seq_counter_ ++; 
		HDR_COPE(*res_pkt)->ctype_ = COPE_DATA;
		hdr_xored_pkt.local_seq_num_ = local->local_seq_counter_;
	    }
	  
	    if(HDR_CMN(cope_iter->get_pkt())->size() > max_size) {

		max_size = HDR_CMN(cope_iter->get_pkt())->size();
		*max_size_pkt = cope_iter->get_pkt();
	    }

	    Packet* nonack_pkt = cope_iter->get_pkt()->copy();
	    // if( node_->nodeid() == 11) {
		
	    	// Packet* temp = nonack_pkt;	    
	    	// cout << "Enc->time: " << CUR_TIME
	    	//      << " node: " << node_->nodeid()
	    	//      << " uid: " << HDR_CMN(temp)->uid_
	    	//      << " ptype: " << HDR_CMN(temp)->ptype()
	    	//      << " size " << HDR_CMN(temp)->size()
	    	//      << " prev: " << ETHER_ADDR(HDR_MAC802_11(temp)->dh_ta)
	    	//      << " next: " << HDR_CMN(temp)->next_hop()
	    	//      << " num: " << (int)HDR_COPE(temp)->encoded_num_
	    	//      << " loc: " << hdr_xored_pkt.local_seq_num_
	    	//      << " pkt: " << HDR_CMN(*res_pkt)->uid_;
	    

	    	// if(HDR_CMN(temp)->ptype() == PT_TCP)
	    	//     cout << " TCP seq: " << HDR_TCP(temp)->seqno();
	    	// else if(HDR_CMN(temp)->ptype() == PT_ACK)
	    	//     cout << " ACK seq: " << HDR_TCP(temp)->seqno();
	    	// else if(HDR_CMN(temp)->ptype() == PT_DSR)
	    	//     cout << " DSR seq: " << HDR_TCP(temp)->seqno();
	    	// cout << endl;	    
	    // }

	    // enque the copy of packet into nonAckQueue
	    hdr_xored_pkt.retx_counter_ =
		non_acks_->enqueue(hdr_xored_pkt.nexthop_,
				   hdr_xored_pkt.local_seq_num_,
				   nonack_pkt);

	    
	    append_xored_pkt(cope_iter->get_pkt(), 
			     hdr_xored_pkt,
			     *res_pkt);	 
        
	    COPE_GET_NEXT(cope_iter, cope_iter);
	} while (cope_iter != NULL );     
	
	return 1;//represent a encoded packet


    } else {
        //can send the native packet directly, free the copy and return p
        return 0; //represent a native packet
    }
}

/**
 * called by traverse_remained_nbs, return encodable or not 
 */
int COPE::encodable(char type , 
                    int nb_iter_id ,
                    nb_pkt_head * encode_next_hops ) {
   
    // denote the candidate packet can be encoded with the prob of 1
    double candidate_prob = 1;
    
    // opposite with prob, denote the probability of an already encoded packet
    // having the checked encoding candidate
    

    
    // get a candidate
    list<Packet*> * pkt_q = cope_prq_->cope_vir_table_->get_vir_pktq(nb_iter_id, type);
     
    if(pkt_q == NULL)
	return 0;
    Packet * pkt_candidate = pkt_q->front();
    // if(pkt_candidate) {
    // 	cout << HDR_CMN(pkt_candidate)->uid_
    // 	     << " " << HDR_CMN(pkt_candidate)->cope_pkt_id();
    // 	if(HDR_COPE(pkt_candidate)->ctype_ == COPE_CTRL)
    // 	    cout << " ctrl";
    // 	else if(HDR_CMN(pkt_candidate)->ptype() == PT_TCP)
    // 	    cout << " tcp" << endl;
    // 	else if(HDR_CMN(pkt_candidate)->ptype() == PT_ACK)
    // 	    cout << " ack" << endl;
    // 	else if(HDR_COPE(pkt_candidate)->ctype_ == COPE_RETX)
    // 	    cout << " crx" << endl;
    // 	else if(HDR_COPE(pkt_candidate)->ctype_ == COPE_DATA)
    // 	    cout << " cope" << endl;
    // 	else
    // 	    cout << endl;
    // }
    
    // iterate each packet in {NextHops} and check the encoded candidate
    // can be encoded together or not, prob will be computed accumulately
    COPENeighborPkt * encoded_pkt_iter;
    COPE_GET_HEAD(encode_next_hops, encoded_pkt_iter);
	    
    for (; encoded_pkt_iter != NULL;) {
       
	if((pkt_info_->get_prob(nb_iter_id, encoded_pkt_iter->get_pkt_id()))  
	   == true) {
	    // neighbor nb_iter_id has this specific encoded pkt
	    // keep prob unchaged, which means prob = prob * 1
	    candidate_prob = candidate_prob * 1.0;
	    
	} else {
	    // check the probability of nb_iter_id has this encoded pkt 
	    int pkt_src_ip =  HDR_IP(encoded_pkt_iter->get_pkt())->saddr();     
	    candidate_prob = 
		candidate_prob * prob_guess_->get_prob_guess(pkt_src_ip,
							     nb_iter_id);	    
	} 

	// 1. Check the nb_iter_id has all already encoded packet,
	//    so that it can decode ------------if
	// 2. Check the nb_pkt_iter->get_id() (the nexthop of an 
	//    already encoded item) can decode new_encoded_pkt or 
	//    not-------------------------------else

	if(candidate_prob <= G ) {	
   
	    return 0; // no need to other have encoded packets

	} else {	  
	    double old_prob = encoded_pkt_iter->get_encode_prob();
	    double cur_prob, new_prob;
	    
	    if(pkt_info_->get_prob(encoded_pkt_iter->getid(),
				    HDR_CMN(pkt_candidate)->cope_pkt_id())) {

	        cur_prob = 1.0;
		new_prob = cur_prob * old_prob;
	      
	    } else {
		// check the probability of nb_iter_id has pkt 
		int pkt_src_ip = HDR_IP(pkt_candidate)->saddr();
		cur_prob = 
		    prob_guess_->get_prob_guess(pkt_src_ip,
						encoded_pkt_iter->getid());	
		new_prob = cur_prob * old_prob;
	
	    }
	    if( new_prob <= G ) 	     
		return 0;  // no need to check any more 
	}

	COPE_GET_NEXT(encoded_pkt_iter,encoded_pkt_iter);
    }

           
    //put this packet into cope_next_hops, 
    //whoes pkts will be encoded later
    COPE_ND_INSERT(COPENeighborPkt, 
		   encode_next_hops,
		   nb_iter_id, 
		   pkt_candidate);
    
    // update the encode_prob for each element in {NextHops}/pkt_candidate
    COPE_GET_HEAD(encode_next_hops, encoded_pkt_iter);
    int pkt_src_ip = HDR_IP(pkt_candidate)->saddr();

    while(encoded_pkt_iter != NULL) {
        if(encoded_pkt_iter->getid() != nb_iter_id) {
	    // when no this packet exists in the packet info, 
	    // update the prob of already encoded packet - pkt_candidate,
	    if(!(pkt_info_->get_prob(encoded_pkt_iter->getid(),
				     HDR_CMN(pkt_candidate)->cope_pkt_id())))   
		encoded_pkt_iter->
		    update_encode_prob(encoded_pkt_iter->get_encode_prob()
				       * 
				       prob_guess_->get_prob_guess(pkt_src_ip, 
								   encoded_pkt_iter->
								   getid()));
	} else {
	    encoded_pkt_iter->update_encode_prob(candidate_prob);
	}
	COPE_GET_NEXT(encoded_pkt_iter,encoded_pkt_iter);
    }
   
    return 1; //encodable
}

/**
 * called by encode, traverse all {Neighbors} - {NextHops} pkts 
 */
void COPE::traverse_remained_nbs(char type,
                                 nb_pkt_head * encode_next_hops,
				 nb_head * remain_nb_list ) {         
    COPENeighbor * nb_iter;
    int nb_iter_id;
    // a packet is encodable or not, undecodable by default
    bool encodable_tag = 0;  

    COPE_GET_HEAD(remain_nb_list, nb_iter);

    while ( nb_iter != NULL ) {
	nb_iter_id = nb_iter->getid();
	encodable_tag = encodable(type, nb_iter_id, encode_next_hops );

	COPE_GET_NEXT(nb_iter, nb_iter);

	if(encodable_tag == 1) {      
	    // delete this neighbor from left list, because it is already
	    // regarded as a encoded next hop
	    COPE_ND_DELETE(COPENeighbor, *remain_nb_list, nb_iter_id);
	} 
    }
}

/*
 * During the append xored header process, simulate xor all encode packet
 * together and store the encoded result to res_pkt, also delete the packets
 * from output queue and virtual queue
 */
void COPE::append_xored_pkt(Packet * del_pkt,
			    hdr_xored_t xored, 
			    Packet * res_pkt ) {

    /* xor all pkts together and store it to res_pkt, just simulate this!*/
    // XOR......
    u_int8_t index = HDR_COPE(res_pkt)->encoded_num_;
    /* Assemble hdr_xored_pkt into pkt's cope header */
    HDR_COPE(res_pkt)->xoreds_[index].pkt_id_ = xored.pkt_id_;
    HDR_COPE(res_pkt)->xoreds_[index].nexthop_ = xored.nexthop_;
    HDR_COPE(res_pkt)->xoreds_[index].local_seq_num_ = xored.local_seq_num_;
    HDR_COPE(res_pkt)->xoreds_[index].retx_counter_ = xored.retx_counter_;
    HDR_COPE(res_pkt)->xoreds_[index].ppkt_ = del_pkt;
    HDR_COPE(res_pkt)->encoded_num_ ++;
    HDR_CMN(res_pkt)->size() += sizeof(hdr_xored_t);
        
    /*
     * dequeue encoded packet from output queue, xor all packets together,
     * just simulate this encoding operation, this operation will also 
     * delete the corresponding pkt in virtual queue
     */
    
    if( cope_prq_->cope_dequeue_item(del_pkt) != NULL ) {
	cope_prq_->cope_vir_table_->remove_vir_pkt(del_pkt);
    }
    //free(del_pkt);
}

void COPE::append_state_report(Packet * p) { 
    Node * tnode = (node_->nodehead_).lh_first;
    hdr_report_t* rpt;

    for (; tnode; tnode = tnode->nextnode() ) {
        /*
	 * get_report() should return false if nodeid doesn't exist
	 */
	if(tnode->nodeid() == node_->address())
	    continue;
	rpt = pkt_pool_->get_report(tnode->nodeid());

	if(rpt != NULL) {
	    u_int8_t index = HDR_COPE(p)->report_num_;
	    HDR_COPE(p)->reports_[index].src_ip_ = rpt->src_ip_;
	    HDR_COPE(p)->reports_[index].last_pkt_ = rpt->last_pkt_;
	    HDR_COPE(p)->reports_[index].bit_map_ = rpt->bit_map_;
	    HDR_COPE(p)->report_num_ ++;
	    // cout << HDR_COPE(p)->report_num_  << endl;
	    HDR_CMN(p)->size() += sizeof(hdr_report_t);
	  
	    free(rpt);
	}
    }
}

void COPE::append_acks(Packet * p) {
    hdr_ack_t* ack;
    nb_head neighbor_list;
    LIST_INIT(&neighbor_list);
    getNeighborList(&neighbor_list);

    COPENeighbor * nb_iter; 
    COPE_GET_HEAD(&neighbor_list, nb_iter); 

    while(nb_iter != NULL){
	ack = pend_acks_->get_pend(nb_iter->getid(), this);	
	if(ack != NULL) {
	    //Assemble hdr_pend into pkt's cope header
	    u_int8_t index = HDR_COPE(p)->ack_num_;
	    HDR_COPE(p)->acks_[index].neighbor_ = ack->neighbor_;
	    HDR_COPE(p)->acks_[index].last_ack_ = ack->last_ack_;
	    HDR_COPE(p)->acks_[index].ack_map_ = ack->ack_map_;
	    HDR_COPE(p)->ack_num() = HDR_COPE(p)->ack_num() + 1;
	    HDR_CMN(p)->size() += sizeof(hdr_ack_t);
	  
	    free(ack);
	}
	COPE_GET_NEXT(nb_iter, nb_iter);
    }
    COPE_ND_CLEAR(COPENeighbor, &neighbor_list);
}


int COPE::receivable( Packet** recv_pkt) {
    // can decode by default
    int decodable = 1;

    // native packet by default
    int native = 1;

    /* 
     * update the packet info according to state field, 
     * and delete these state reports after updating
     */ 
    extract_state_report(*recv_pkt);

    /* 
     * update the non ack queue according to ack field, 
     * and delete these acks after updating
     */ 
    extract_acks(*recv_pkt);

    /* If it is a control packet, just send it to CtrlAgent and drop it */
    if(HDR_COPE(*recv_pkt)->ctype_ == COPE_CTRL) {
       
        return 4; // as a non-receivable packet

    }
    
    // Decode only if it is an encoded packet
    if(HDR_COPE(*recv_pkt)->encoded_num_ > 1) {      
	/* 
	 * the recv_pkt will be the decoded result if it is decodable,
	 * but here we just use pointer p instead, since we don't need
	 * to real decode the packet data, just clear all xored header
	 * of p is enough 
	 *
	 * if it is not decodable, the result will be copy of original
	 * encoded p, keeping the xored header alive, in order to put
	 * its copy into packet pool
	 */

        native = 0;
	// the recv_pkt will be freed if return value of decode is zero
	decodable = decode(recv_pkt);
    }
    
    /* the native packet should be receivable */
    if( native == 1 ) {
        int id = HDR_CMN(*recv_pkt)->next_hop();

	if(node_->nodeid() == id || id < 0)

	    return 1; // native and receivable, can be sent out
	else
	    return 2; // native but non-receivable
   
    } else if (decodable == 1 ) {      
        return 3; //decodable, receivable, and decoded packet can be sent out 
	
	/* 
	 * Non-receivable: include two situation
	 * 1. can not decode  2, decodable but I am not the receiver 
	 * 3. decodable but the decoded packet on longer exist
	 */

    } else {
      
        return decodable; // 0 or -1
        // return -1 for overhear encoded packet, statistic using
	// 0 is overhear non-decodable packet

    } 
}


/**
 * return the packet decodable status and the decoded_pkt pointer,
 * 0 - Non-decodable(include the decoded packet has been dropped 
 * at sender because of over retransmission, we regard this situation
 * as a non-decoydable case) & (overhear packet) & (can not decode); 
 * 1 - Decodable and return a valid packet;
 * But in a simulation, no real decode operation, so just set
 * a xor-header cleared p as a result is enough
 */
int COPE::decode(Packet** decoded_pkt) {
    int decodable = 1; // decodable by default
    int overhear = 1; // overhear by default
  
    int decode_target = -1;
    u_int16_t loc;
    u_int8_t rc;

    int prev =  ETHER_ADDR(HDR_MAC802_11(*decoded_pkt)->dh_ta);

    int counter = 0;
    for(int j = 0; j < (int)HDR_COPE(*decoded_pkt)->encoded_num_; j ++) {
	if(HDR_COPE(*decoded_pkt)->xoreds_[j].nexthop_ == node_->nodeid())
	    counter ++;
    }
    if(counter == 0)
	return 0;
    
    for(int i = 0; i < (int)HDR_COPE(*decoded_pkt)->encoded_num_; i ++) {
	// if(HDR_CMN(*decoded_pkt)->uid_ == 7130 && node_->nodeid() == 2)
	//     cout << "";
	// cout << node_->nodeid() << "for-------------decode: "
	//      << HDR_CMN(*decoded_pkt)->uid_
	//      << " num: " << (int)HDR_COPE(*decoded_pkt)->encoded_num_
	//      << " nexthop: " << HDR_COPE(*decoded_pkt)->xoreds_[i].nexthop_
	//      << endl;
	// Packet* p = HDR_COPE(*decoded_pkt)->xoreds_[i].ppkt_;
	// if(HDR_COPE(*decoded_pkt)->xoreds_[i].nexthop_ == node_->nodeid()) {
	//     cout << "fDec->time: " << CUR_TIME
	// 	 << " node: " << node_->nodeid()
	// 	 << " uid: " << HDR_CMN(p)->uid_
	// 	 << " ptype: " << HDR_CMN(p)->ptype()
	// 	 << " ctype: " << (int)HDR_COPE(p)->ctype_
	// 	 << " size " << HDR_CMN(p)->size()
	// 	 << " prev: " << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
	// 	 << " next: " << HDR_CMN(p)->next_hop();
	//     if(HDR_CMN(p)->ptype() == PT_TCP)
	// 	cout << " TCP seq: " << HDR_TCP(p)->seqno();
	//     else if(HDR_CMN(p)->ptype() == PT_ACK)
	// 	cout << " ACK seq: " << HDR_TCP(p)->seqno();
	//     cout << endl;
	// }

	// still can decode and node is not the nexthop, decode this pkt out 
	if(HDR_COPE(*decoded_pkt)->xoreds_[i].nexthop_ != node_->nodeid()) {
	    //check whether the nexthop exists in packet pool	  
	    Packet * encode_pkt =
		pkt_pool_->get_packet(HDR_COPE(*decoded_pkt)->xoreds_[i].pkt_id_);
	    
	    //opps! can not decode
	    if( encode_pkt == NULL && decodable != 0)
	        decodable = 0;
	    
	} else {

	    loc = HDR_COPE(*decoded_pkt)->xoreds_[i].local_seq_num_;
	    rc = HDR_COPE(*decoded_pkt)->xoreds_[i].retx_counter_;
	    overhear = 0;
	    decode_target = i;
	}

	HDR_CMN(*decoded_pkt)->size() -= sizeof(hdr_xored_t);
    }

    Packet * temp = pkt_pool_->get_packet(HDR_COPE(*decoded_pkt)->xoreds_[decode_target].pkt_id_);
    
    //non-decodable include three cases as said above
    if(overhear == 1 || decodable == 0) {
	
      	if( decodable == 0 ) {
	    if (rc >= RETRANSMIT_TIMES)
	    	pend_acks_->enqueue_pend(prev, loc, true, this);

	    // cout << node_->nodeid() << "---non-decode: " << decode_target << endl;
	    if(!temp)
	    	Packet::free(HDR_COPE(*decoded_pkt)->xoreds_[decode_target].ppkt_);
	    return decodable; // non decodable packet

	} else {
	    // cout << node_->nodeid() << " ---over-hear---" << endl;
	    return -1; //overhear packet
	}
    }
    
    // Decodable packet, return a decoded packet whose nexthop is me

    
    if(!temp)
//    cout << node_->nodeid() <<  "---decode: " << decode_target << endl;
    	temp = HDR_COPE(*decoded_pkt)->xoreds_[decode_target].ppkt_;
    else {
    	temp = temp->copy();
	//	HDR_COPE(*decoded_pkt)->ctype_ = COPE_RETX;
    }
    Packet::free(*decoded_pkt);
    
    *decoded_pkt = temp;
    // HDR_COPE(*decoded_pkt)->encoded_num_ = 0;


    // cout << "Dec->time: " << CUR_TIME
    // 	 << " node: " << node_->nodeid()
    // 	 << " uid: " << HDR_CMN(temp)->uid_
    // 	 << " ptype: " << HDR_CMN(temp)->ptype()
    // 	 << " size " << HDR_CMN(temp)->size()
    // 	 << " prev: " << ETHER_ADDR(HDR_MAC802_11(temp)->dh_ta)
    // 	 << " next: " << HDR_CMN(temp)->next_hop()
    // 	 << " num: " << (int)HDR_COPE(temp)->encoded_num_;

    // if(HDR_CMN(temp)->ptype() == PT_TCP)
    // 	cout << " TCP seq: " << HDR_TCP(temp)->seqno();
    // else if(HDR_CMN(temp)->ptype() == PT_ACK)
    // 	cout << " ACK seq: " << HDR_TCP(temp)->seqno();
    // cout << endl;
    
    // cout << "Decode: ---addr: " decoded_pkt << endl;
    //enque pend the non retransmission 
    if( HDR_COPE(*decoded_pkt)->ctype_ != COPE_RETX )
	pend_acks_->enqueue_pend(prev, loc, false, this);
    else
	pend_acks_->enqueue_pend(prev, loc, true, this);

    return decodable;
}

/**
 * update pkt_info for a node according to the state report, 
 * and delete state report field in cope header
 */
void COPE::extract_state_report(Packet * p) {
    // check whether there is state report in this packet
    if(HDR_COPE(p)->report_num_ == 0)
	return;

    int src_node_id = ETHER_ADDR(HDR_MAC802_11(p)->dh_ta);

    for(int i = 0; i < HDR_COPE(p)->report_num_; i ++) {
	pkt_info_->update_pkt_info(HDR_COPE(p)->reports_[i], src_node_id, node_->nodeid());
	HDR_CMN(p)->size() -= sizeof(hdr_report_t);
    }
    
    // update the prob_guess_ use the updated pkt_info
    nb_head neighbor_list ;
    LIST_INIT(&neighbor_list);
    getNeighborList(&neighbor_list);
    prob_guess_->up_prob_info(src_node_id, 
			      &neighbor_list,
			      cope_prq_->cope_vir_table_,
			      pkt_info_);
    COPE_ND_CLEAR(COPENeighbor, &neighbor_list);

    HDR_COPE(p)->report_num_ = 0;
}

/**
 * if nodeid  == neighbor, update non-ack queue for the node according to the
 * ack information, and then delete all ack information field in cope header
 */

void COPE::extract_acks(Packet * p) {    
    // check whether there is ack block in this packet
    if((int)HDR_COPE(p)->ack_num_ == 0)
        return;
    // get the previous hop to delete it from NonAckQueue if acked
    int prev_hop = ETHER_ADDR(HDR_MAC802_11(p)->dh_ta);
    Packet* pkt = NULL;
 
    for(int i = 0; i < HDR_COPE(p)->ack_num_; i ++) {
        if(HDR_COPE(p)->acks_[i].neighbor_ == node_->nodeid()) {
            int last = HDR_COPE(p)->acks_[i].last_ack_;
            int loc = last - ACKMAP_SIZE;
	    // if(node_->nodeid() == 4 && prev_hop == 5) {
	    // 	cout << "Extack->time: " << CUR_TIME
	    // 	     << " node: " << node_->nodeid()
	    // 	     << " uid: " << HDR_CMN(p)->uid_
	    // 	     << " ptype: " << HDR_CMN(p)->ptype()
	    // 	     << " size " << HDR_CMN(p)->size()
	    // 	     << " prev: " << ETHER_ADDR(HDR_MAC802_11(p)->dh_ta)
	    // 	     << " next: " << HDR_CMN(p)->next_hop();
	    // 	if(HDR_CMN(p)->ptype() == PT_TCP)
	    // 	    cout << " TCP seq: " << HDR_TCP(p)->seqno();
	    // 	else if(HDR_CMN(p)->ptype() == PT_ACK)
	    // 	    cout << " ACK seq: " << HDR_TCP(p)->seqno();
	    // 	cout << endl;

		
	    // 	cout << "ExtACK: last: " << last
	    // 	     << " ackmap: " << bitset<8>(HDR_COPE(p)->acks_[i].ack_map_)
	    // 	     << endl;		
	    // }
            for(int j = 0; j <= ACKMAP_SIZE; j ++) {
                // cout << bitset<8>(HDR_COPE(p)->acks_[i].ack_map_) << endl;
                if(loc > 0) {
                    if((HDR_COPE(p)->acks_[i].ack_map_ & 0x80)
                       || (loc == last)) {
                        u_int8_t rc = non_acks_->lookup_packet(prev_hop, loc, &pkt);
                        if(pkt == NULL) {
                            HDR_COPE(p)->acks_[i].ack_map_ <<= 1;
                            loc ++;
                            continue;
                        }
                        stop_timer(prev_hop, loc);
                        if(rc > 0) {
                            if(cope_prq_->cope_dequeue_item(pkt))
                                cope_prq_->cope_vir_table_->remove_vir_pkt(pkt);
                        }
                        non_acks_->delete_entry(prev_hop, loc);
                    } else {
                        retrasmit(prev_hop, loc);
                    }
                }
                HDR_COPE(p)->acks_[i].ack_map_ <<= 1;
                loc ++;
            }
        }
	HDR_CMN(p)->size() -= sizeof(hdr_ack_t);	
    }
    HDR_COPE(p)->ack_num_ = 0;
}


/*
 * This function should be called whenever there is a packet sent out.
 */
void COPE::set_pkt_header(Packet* p) {
    struct hdr_cope* hc = HDR_COPE(p);
    hc->encoded_num_ = 0;
    // if(HDR_COPE(p)->ctype_ != COPE_CTRL) {
    hc->report_num_ = 0;
    hc->ack_num_ = 0;
    // }

    int pktid = 0;
    struct hdr_cmn* ch = HDR_CMN(p);

    /*
     * There would be a problem when cope_seq_num_ >= 2^16, so we should
     * reset cope_seq_num_ to 0 when cope_seq_num_ == 2^16 - 1.
     */
    
    if(cope_index_ == ((1 << 16) - 1)) // problems!!!
	cope_index_ = 0;
    cope_index_ ++;
    HDR_CMN(p)->cope_seq_num() = cope_index_;

    /*
     * pkt-id is the hash of source ip address and ip sequence number,
     * HASH_JEN_MIX (hash function in uthash) is used to generate pkt-id.
     */
    nsaddr_t src = HDR_IP(p)->saddr();
    u_int16_t seq = ch->cope_seq_num();
    
    HASH_JEN_MIX(src, seq, pktid);
 
    ch->cope_pkt_id() = pktid;
    //    cout << "set_pkt_header: " << pktid << endl;
}


void COPE::start_timer(Packet *p, double timeout) {
    u_int8_t rc;
    for(int i = 0; i < HDR_COPE(p)->encoded_num_; i ++) {
    	NonAckTimer* timer = new NonAckTimer(this);
	rc = HDR_COPE(p)->xoreds_[i].retx_counter_;
	if( rc == 0)
	    rc = 1;
	else
	    rc <<= 1;
    	timer->start(timeout * rc,
    		     HDR_COPE(p)->xoreds_[i].nexthop_,
    		     HDR_COPE(p)->xoreds_[i].local_seq_num_);
	
    	non_ack_timers_->push_back(timer);
    }
}

void COPE::stop_timer(Packet* p) {
    Scheduler &s = Scheduler::instance();
    Event* e = s.lookup(p->uid_);
    ((CopeTimer*)(e->handler_))->stop(); // maybe problems!!!
}

void COPE::stop_timer(int nodeid, u_int16_t local) {
    list<NonAckTimer*>::iterator it = non_ack_timers_->begin();

    for( ; it != non_ack_timers_->end(); it ++) {
	if((*it)->nonack_nodeid_ == nodeid 
	   && 
	   (*it)->nonack_local_seqnum_ == local) {
    	    (*it)->stop();
    	    delete (*it);
    	    non_ack_timers_->erase(it);
    	    break;
    	}
    }
}


/*
 * Insert the time-out packet at the head of the output queue and retransmit.
 */
void COPE::non_ack_handler(Event* e) {

    NonAckTimer* t = (NonAckTimer*)(e->handler_);

    int nodeid = t->nonack_nodeid_;
    u_int16_t local = t->nonack_local_seqnum_;
    Packet* p = NULL;
//    u_int8_t rc = non_acks_->get_packet(nodeid, local, &p);
    u_int8_t rc = non_acks_->lookup_packet(nodeid, local, &p);
    
    /*
     * If the retrasmission times bigger than the threshold, stop this timer
     * and delete the packet info in NonAckQueue, then return directly.
     */
    if(p == NULL)
	return;
    
    if(rc >= RETRANSMIT_TIMES) {
	stop_timer(nodeid, local);
	if(cope_prq_->cope_dequeue_item(p) != NULL
	   && HDR_COPE(p)->ctype_ != COPE_CTRL)
	    cope_prq_->cope_vir_table_->remove_vir_pkt(p);

	// cout <<CUR_TIME << " COPE: delete non ack since rc > RTIMES" << endl;
        non_acks_->delete_entry(nodeid, local);
	return; 
    }
    //cout << HDR_CMN(p)->uid_ << endl;
    if(cope_prq_->cope_dequeue_item(p) != NULL
       && HDR_COPE(p)->ctype_ != COPE_CTRL)
        cope_prq_->cope_vir_table_->remove_vir_pkt(p);

    list<NonAckTimer*>::iterator it = non_ack_timers_->begin();
    for( ; it != non_ack_timers_->end(); it ++) {
    	if((*it)->nonack_nodeid_ == nodeid 
	   && 
	   (*it)->nonack_local_seqnum_ == local) {
	    // (*it)->stop();
    	    delete (*it);
    	    non_ack_timers_->erase(it);
    	    break;
    	}
    }
    
    Packet * cp = p->copy();
    HDR_COPE(cp)->ctype_ = COPE_RETX;

    u_int16_t loc = non_acks_->get_local_seq(HDR_CMN(cp)->next_hop(), 
					     HDR_CMN(cp)->cope_pkt_id()); 
   

    
    HDR_COPE(cp)->xoreds_[0].local_seq_num_ = loc;
   
    recv(cp, &h_cope_);
}

void COPE::retrasmit(int nodeid, u_int16_t local) {
    Packet* p = NULL;
    u_int8_t rc = non_acks_->lookup_packet(nodeid, local, &p);

    /*
     * If the retrasmission times bigger than the threshold, stop this timer
     * and delete the packet info in NonAckQueue, then return directly.
     */
    if(p == NULL)
	return;
    
    if((int)rc >= RETRANSMIT_TIMES) {
    	stop_timer(nodeid, local);
	
	if( cope_prq_->cope_dequeue_item(p)  != NULL )
	    cope_prq_->cope_vir_table_->remove_vir_pkt(p);
	
        non_acks_->delete_entry(nodeid, local);
    	return; 
    }

    if( cope_prq_->cope_dequeue_item(p) != NULL )
        cope_prq_->cope_vir_table_->remove_vir_pkt(p);
    
    stop_timer(nodeid, local);
  
      
    Packet * cp = p->copy();
    HDR_COPE(cp)->ctype_ = COPE_RETX;
    
    u_int16_t loc = non_acks_->get_local_seq(HDR_CMN(cp)->next_hop(), 
					     HDR_CMN(cp)->cope_pkt_id()); 

    HDR_COPE(cp)->xoreds_[0].local_seq_num_ = loc;
    
    // cout << "Retx->time: " << CUR_TIME
    //      << " node: " << node_->nodeid()
    //      << " uid: " << HDR_CMN(cp)->uid_
    // 	 << " rc: " << (int)rc
    //      << " ptype: " << HDR_CMN(cp)->ptype()
    //      << " size " << HDR_CMN(cp)->size()
    //      << " prev: " << ETHER_ADDR(HDR_MAC802_11(cp)->dh_ta)
    //      << " next: " << HDR_CMN(cp)->next_hop();

    // if(HDR_CMN(cp)->ptype() == PT_TCP)
    //     cout << " TCP seq: " << HDR_TCP(cp)->seqno();
    // else if(HDR_CMN(cp)->ptype() == PT_ACK)
    //     cout << " ACK seq: " << HDR_TCP(cp)->seqno();
    // cout << endl;

    recv(cp, &h_cope_);
}

/*
 * allocate a control packet and transmit it
 */
void COPE::ctrl_pkt_handler(Handler * h) {


    Packet * cp = Packet::alloc();
    //Agent::initpkt(cp);
    HDR_CMN(cp)->uid() = Agent::uidcnt_++;
    
    // set Common Header
    hdr_cmn* ch = HDR_CMN(cp);
    //    ch->uid() = 0;
    ch->ptype() = PT_COPE;
    ch->size() = 10;
    ch->iface() = -2;
    ch->error() = 0;
    ch->direction_ = hdr_cmn::DOWN; //DOWN
    ch->next_hop_ =  (int)IP_BROADCAST;
    //ch->prev_hop_ = node_->address();
	
    //set ip header
    hdr_ip* iph = HDR_IP(cp);
    iph->saddr() = node_->address();
    iph->daddr() = (int)IP_BROADCAST;	
    ch->size() += IP_HDR_LEN;

    // mac header 
    hdr_mac* dh = HDR_MAC(cp);
    mac_->hdr_dst((char*) dh, MAC_BROADCAST);
    mac_->hdr_src((char*) dh, mac_->addr());
    dh->ftype_ = MF_DATA;
    ch->size() += MAC_HDR_LEN;

    // set cope header
    HDR_COPE(cp)->ctype_ = COPE_CTRL;
    HDR_COPE(cp)->encoded_num_ = 0;
    HDR_COPE(cp)->report_num_ = 0;
    HDR_COPE(cp)->ack_num() = 0;
 
    /* add the state report and acks info */
    // append_state_report(cp);
    // append_acks(cp);

    if(HDR_COPE(cp)->report_num_ == 0 && HDR_COPE(cp)->ack_num_ == 0) {
	Packet::free(cp);
	return;
    }
    
  
    
    // call the recv of this function
 
    recv(cp, &h_cope_);
}

#endif
